/*
 *   Clovis
 *   Copyright (C) 2008 SFWOL
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef __CSTRING_H
#define __CSTRING_H

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

#include "CInteger.h"
#include "CFloat.h"

namespace clovis {

	namespace core {

		class CInteger; // This is done to skip infinite inclusions
		class CFloat;

		/*!
		 * \brief The main String type used into Clovis
		 *
		 * CString is the String type used into Clovis. It has the same value as an std::string but with
		 * usefull methods that you can call averywhere in your source code.
		 * You can use it as a standard type.
		 * \code
		 * CString my_var = "foo";
		 * \endcode
		 */
		class CString : public ClovisVariable {

			private:

				std::string value;	// Internal value

			public:

				/*!
				 * Convert the current string to a std::string.
				 * \return A std::string.
				 */
                std::string toStdString();

                /*!
                 * Constructeur ou l'on souhaite attribuer un nom
                 * \arg Le nom de l'objet
                 * \arg La valeur de l'objet
                 */
                CString(std::string name , std::string value);

				/*!
				 * Empty constructor, initialized to ''
				 */
				CString();

				/*!
				 * Objected oriented constructor
				 * \code
				 * CString my_var("foo");
				 * \endcode
				 */
				CString(std::string value);

				/*!
				 * Standard type constructor
				 * \code
				 * CString my_var = "foo";
				 * \endcode
				 */
				CString(const char *value);

				/*!
				 * Get The class type in a std::string variable.
				 * \return "CString"
				 */
				std::string getClass();

				/*!
				 * To change the value with a standard std::string
				 * \arg value The value to assign
				 */
				void operator = (std::string value);

				/*!
				 * To change the value with a CString
				 * \arg value The value to assign
				 */
				void operator = (CString value);

				/*!
				 * \todo TODO !!!!!!!
				 */
				void operator = (const char *value);

                /*!
                 * Return a Cstring which is the concatenation between the current value and the value passed in argument.
                 * \arg value The value to concatenate
                 * \return The concatenation between current and argument value.
                 */
                CString operator + (CString value);

				/*!
                 * Return a Cstring which is the concatenation between the current value and the value passed in argument.
                 * \arg value The value to concatenate
                 * \return The concatenation between current and argument value.
                 * \see See CInteger's documentation for more informations about CInteger to CString conversion.
                 */
                CString operator + (CInteger value);

				/*!
                 * Return a Cstring which is the concatenation between the current value and the value passed in argument.
                 * \arg value The value to concatenate
                 * \return The concatenation between current and argument value.
				 * \see See CFloat's documentation for more informations about CFloat to CString conversion.
                 */
                CString operator + (CFloat value);

				/*!
				 * Clear the content of the current CString (same effect as = "").
				 */
				void clear();

				/*!
				 * Concatenate current CString with another CString (the argument is placed behind the current CString).
				 * \arg to_add The string we want to concatenate with.
				 */
				void operator += (CString to_add);

				/*!
				 * Concatenate current CString with another CString (the argument is placed behind the current CString).
				 * \arg to_add The string we want to concatenate with.
				 * \see See CInteger's documentation for more informations about CInteger to CString conversion.
				 */
				void operator += (CInteger to_add);

				/*!
				 * Concatenate current CString with another CString (the argument is placed behind the current CString).
				 * \arg to_add The string we want to concatenate with.
				 * \see See CFloat's documentation for more informations about CFloat to CString conversion.
				 */
				void operator += (CFloat to_add);

				/*!
				 * Comparison between two CString.
				 * \return A boolean : true if the values are the same, false if not.
				 */
				bool operator == (CString compare_to);

				/*!
				 * Comparison between a CString and a CInteger.
				 * \return A boolean : true if the values are the same, false if not.
				 * \see See CInteger's documentation for more informations about CInteger to CString conversion.
				 */
				bool operator == (CInteger compare_to);

				/*!
				 * Comparison between a CString and a CInteger.
				 * \return A boolean : true if the values are the same, false if not.
				 * \see See CFloat's documentation for more informations about CFloat to CString conversion.
				 */
				bool operator == (CFloat compare_to);

				/*!
				 * Comparison between two CString.
				 * \return A boolean : true if the values are different, true if they are the same.
				 */
				bool operator != (CString compare_to);

				/*!
				 * Comparison between a CString and a CInteger.
				 * \return A boolean : true if the values are the same, false if not.
				 * \see See CInteger's documentation for more informations about CInteger to CString conversion.
				 */
				bool operator != (CInteger compare_to);

				/*!
				 * Comparison between a CString and a CInteger.
				 * \return A boolean : true if the values are the same, false if not.
				 * \see See CFloat's documentation for more informations about CFloat to CString conversion.
				 */
				bool operator != (CFloat compare_to);

				/*!
				 * Convert CString to a char array (the same way as std::string.c_str()).
				 * \return A const char* version of the current CString.
				 */
				const char* toCharArray();

				/*!
				 * Clean the current string : remove select characters from the beginning and the end of the string
				 * \arg skip The values who wants to remove at the begining and at the end og the CString.
				 */
				void wash(CString skip = " \n\t");

				/*!
				 * Explode the current CString to a std::vector<CString> vector.
				 * \arg delimiter The delimiter we want to use to explode the current CString.
				 * \return A std::vector<CString> who contains all the parts of the exploded CString.
				 */
				std::vector<CString> explode(CString delimiter);

				/*!
				 * Merge a std::vector<CString> vector into a single CString, using a custom delimiter.
				 * \arg cstring_vector A std::vector<Cstring> vector.
				 * \arg delimiter The CString that we want to add between every parts of the vector.
				 * \return A CString version of the vector with delimiter between each elements.
				 */
				CString implode(std::vector<CString> cstring_vector, CString delimiter);

				/*!
				 * Get the char at the givent position in the CString.
				 * \arg position The position of the character we want to get (start at 0).
				 * \return A char value, corresponding to the value at the wanted position.
				 */
				char charAt(CInteger position);

				/*!
                 * Return the number of characters int the CString.
                 * \return A CInteger.
                 */
                CInteger size();

				/*!
				 * Maximum size of CString without reallocation (the same as std::string).
				 * The following code :
				 * \code CString var = "foo";
				 * std::cout << var.maxSize().toInt() << std::endl;
				 * var = "y";
				 * std::cout << var.maxSize().toInt() << std::endl;
				 * var = "Hello World";
				 * std::cout << var.maxSize().toInt() << std::endl;
				 * \endcode
				 * Will produce the following output :
				 * \code 3
				 * 3
				 * 11
				 * \endcode
				 */
                CInteger maxSize();

				/*!
				 * Ask if the current CString is empty or not.
				 * \return A boolean : true = the CString is empty ; false = the CString is not empty.
				 */
                bool isEmpty();

				/*!
				 * \todo TODO !!!!!!
				 */
                void insert(CString string_to_add);

				/*!
				 * \todo TODO !!!!!!
				 */
                void replace(CInteger selection_beginning, CInteger selection_end, CString replace_with);

				/*!
				 * \todo TODO !!!!!!
				 */
                void replace(CString looking_for, CString replace_with);

				/*!
				 * \todo TODO !!!!!!
				 */
                void remove(CInteger selection_beginning, CInteger selection_end);

                /*!
                 * \todo TODO !!!!!!
                 */
                void remove(CString looking_for);

				/*!
				 * \todo TODO !!!!!!
				 */
                std::vector<CInteger> find(CString element);

				/*!
				 * Find the position of the first occurence of one of the elements passed in argument.
				 * \code
				 * CString var = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
				 * std::cout << "First @ " << var.findFirstOf("oi").toInt() << std::endl;
				 * \endcode
				 * Will print "First @ 1" because there is a 'o' before the first 'i'.
				 * \arg element is a string who contains the characters that we want to find. (case sensitive)
				 * \return The position of the element (start at 0) and -1 if one of the elements cannot be found.
				 */
                CInteger findFirstOf(CString element);

				/*!
				 * Find the position of the last occurence of one of the elements passed in argument.
				 * \code
				 * CString var = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
				 * std::cout << "First @ " << var.findLastOf("oi").toInt() << std::endl;
				 * \endcode
				 * Will print "First @ 54" because there is a 'i' before the last 'o'.
				 * \arg element is a string who contains the characters that we want to find. (case sensitive)
				 * \return The position of the element (start at 0) and -1 if one of the elements cannot be found.
				 */
                CInteger findLastOf(CString element);

				/*!
				 * Find the position of the first occurence of an element who is not passed in argument.
				 * \code
				 * CString var = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
				 * std::cout << "First @ " << var.findFirstNotOf("Lloremit").toInt() << std::endl;
				 * \endcode
				 * Will print "First @ 5".
				 * \arg element is a string who contains the characters that we want to find. (case sensitive)
				 * \return The position of the element (start at 0) and -1 if one of the elements cannot be found.
				 */
                CInteger findFirstNotOf(CString element);

				/*!
				 * Find the position of the last occurence of an element who is not passed in argument.
				 * \code
				 * CString var = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
				 * std::cout << "First @ " << var.findLastNotOf("Lloremit").toInt() << std::endl;
				 * \endcode
				 * Will print "First @ 51".
				 * \arg element is a string who contains the characters that we want to find. (case sensitive)
				 * \return The position of the element (start at 0) and -1 if one of the elements cannot be found.
				 */
                CInteger findLastNotOf(CString element);

				/*!
				 * \todo TODO !!!!!!
				 */
                bool equals(CString string_to_compare_to);

				/*!
				 * Extract the substring in the current CString.
				 * \arg begining The position we start the extraction.
				 * \arg length The length of the CString we wants to extract.
				 * \return The extracted CString.
				 */
                CString substr(CInteger begining, CInteger length);

				/*!
				 * Convert the current CString to a CFloat and returns it.
				 * \return A CFloat value, corresponding to the current CString.
				 * \todo Write more informations about the results.
				 */
                CFloat toCFloat();

				/*!
				 * Convert the current CString to a CInteger and returns it.
				 * \return A CInteger value, corresponding to the current CString.
				 * \todo Write more informations about the results.
				 */
                CInteger toCInteger();

		};

	};

};

#endif
